/*
 Promise：ES6新增的API(构造函数) ，承诺者设计模式
   + 不兼容IE，需要导入 @bable/polyfill 对其进行重写，以此来兼容IE浏览器
   + 基于承诺者模式，有效的去管理异步编程；避免传统上，基于回调函数的方式管理异步编程，所带来的回调地狱问题；尤其是再配合 async/await 语法糖，可以让异步操作看起来和同步一样，管理起来更方便！
 */
// Promise() //TypeError: Promise constructor cannot be invoked without 'new' 作为构造函数，只能被NEW执行，不能作为普通函数执行「扩展：基于class创建的类，是不能当做普通函数执行的」
// new Promise() //TypeError: Promise resolver undefined is not a function  NEW执行的时候，要求Promise中必须传递一个 executor 执行函数

/*
 let p = new Promise([executor])
   私有属性
     + [[PromiseState]] 实例的状态：“pending”准备、“fulfilled”成功、“rejected”失败
     + [[PromiseResult]] 实例的值：undefined、成功的结果、失败的原因
   公有方法 Promise.prototype
     + p.then(onfulfilled, onrejected) 可以根据实例的状态，来决定执行哪个方法
     + p.catch(onrejected) 实例为失败状态，执行传递的onrejected方法
     + p.finally(onfinally) 不论实例的状态是成功还是失败，最后onfinally函数都会执行
     + Symbol(Symbol.toStringTag): "Promise"  控制toString.call检测数据类型返回的结果
  ----
  学习Promise的时候，我们：
    + 要知道如何创建一个promise实例 
    + 并且了解如何修改实例的状态和值
    + 最后掌握then/catch/finally等方法执行的契机及操作过程中的一些细节
 */

/*
 第一种：基于 new Promise 来创建一个 promise 实例
   + 会把传递进来的 executor 函数“立即执行”「同步」
   + 而其会给 executor 函数传递两个实参，我们一般会基于resolve/reject两个形参变量来接收传递的实参
     + resolve/reject接收的实参值都是函数
     + resolve([value])：立即把实例的状态改为fulfilled，实例的值改为[value]
     + reject([reason])：立即把实例的状态改为rejected，实例的值改为[reason]
     + 实例的状态一但被从 pending 改为其它状态值，则后续没有办法再修改此实例的状态和值了
 */
/* 
let p1 = new Promise((resolve, reject) => {
    resolve(100)
    reject(0)
})
p1.then(
    // onfulfilled：p1状态为成功，会触发此函数执行
    (value) => {
        // value 实例的值
        console.log(value)
    },
    // onrejected：p1状态为失败，会触发此函数执行
    (reason) => {
        // reason 实例的值
        console.log(reason)
    }
) 
*/

/* 
console.log(1)
let p1 = new Promise((resolve, reject) => {
    console.log(2)
    reject(0)
    console.log(3)
})
console.log(4)
p1.then(value => {
    console.log(value)
    console.log(5)
}, reason => {
    console.log(reason)
    console.log(7)
})
console.log(6) 
*/

console.log(1)
let p1 = new Promise((resolve, reject) => {
    console.log(2)
    setTimeout(() => {
        console.log(3)
        resolve(100)
        console.log(4)
    }, 1000)
    console.log(5)
})
console.log(6)
p1.then(value => {
    console.log(value)
}, reason => {
    console.log(reason)
})
console.log(7)
p1.then(value => {
    console.log(value)
}, reason => {
    console.log(reason)
})
console.log(8)

//==================================
/*
需求：在项目中，有三个接口请求(串行请求)，现在需要我们分别调用三个接口，完成数据的获取和绑定
  接口1：/api/info  ->  {id:xxx,....}
  接口2：/api/ranking?id=xxx  -> {rank:27}
  接口3：/api/prize?rank=27
*/
/*
// JQ中提供的 $.ajax 方法，就是基于传统的回调函数方式，来管理异步的 XMLHttpRequest 请求
// 也触发了回调地狱
$.ajax({
    url: '/api/info',
    success(data) { //当请求成功，会触发success回调函数执行，data就是从服务器获取的数据
        let { id } = data
        $.ajax({
            url: '/api/ranking?id=' + id,
            success(data) {
                let { rank } = data
                $.ajax({
                    url: '/api/prize?rank' + rank,
                    success(data) {
                        // ...
                    }
                })
            }
        })
    }
})
*/

// Axios是基于Promise方式，来管理异步的 XMLHttpRequest 请求
/* (async () => {
    let { id } = await axios.get('/api/info')
    let { rank } = await axios.get(`/api/ranking?id=${id}`)
    let data = await axios.get(`/api/prize?rank=${rank}`)
    // ...
})() */
/* axios.get('/api/info')
    .then(data => {
        let { id } = data
        return axios.get(`/api/ranking?id=${id}`)
    })
    .then(data => {
        let { rank } = data
        return axios.get(`/api/prize?rank=${rank}`)
    })
    .then(data => {
        // ...
    }) */


/* 需求：编写一个 delay 延迟函数，执行 delay 函数，可以把我们要做的事情延迟一段时间执行 */
/* 
// 传统方案：基于回调函数的方式，管理异步任务执行期间，要处理的事情
const delay = function delay(interval, callback) {
    if (typeof interval === 'function') {
        // 其实传递的函数是要给callback的
        callback = interval
        interval = 1000
    }
    interval = +interval
    if (isNaN(interval)) interval = 1000
    if (typeof callback !== 'function') callback = Function.prototype
    let timer = setTimeout(() => {
        callback()
        clearTimeout(timer)
    }, interval)
}
// 回调地狱：回调函数中嵌套回调函数「不方便阅读和开发维护」
delay(() => {
    console.log('AAA')
    delay(() => {
        console.log('BBB')
        delay(() => {
            console.log('CCC')
        })
    })
}) 
*/

/* 
const delay = function delay(interval = 1000) {
    return new Promise(resolve => {
        let timer = setTimeout(() => {
            resolve()
            clearTimeout(timer)
        }, interval)
    })
}
console.log('start');
(async () => {
    await delay()
    console.log('AAA')
    await delay()
    console.log('BBB')
    await delay()
    console.log('CCC')
})()
// delay()
//     .then(() => {
//         console.log('AAA')
//         return delay()
//     })
//     .then(() => {
//         console.log('BBB')
//         return delay()
//     })
//     .then(() => {
//         console.log('CCC')
//     }) 
*/